package com.yf.exam.websocket.server;

import com.yf.ability.redis.service.RedisService;
import com.yf.ability.websocket.CustomSpringConfigurator;
import com.yf.base.api.exception.ServiceException;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author bool
 */
@Data
@Log4j2
@Component
@ServerEndpoint(value = "/api/socket/exam/{userId}/{examId}/{platform}", configurator = CustomSpringConfigurator.class)
public class ExamEndpoint {

    /**
     * 至少60秒才记录
     */
    public static final Long MIN_TIME = 60L;

    /**
     * 单人会话列表
     */
    public static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap();

    /**
     * Redis
     */
    @Autowired
    private RedisService redisService;


    /**
     * 开始考试
     * @param session
     * @param userId
     * @param examId
     * @param platform
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId,
                       @PathParam("examId") String examId,
                       @PathParam("platform") String platform) {


        log.info("++++++++++考试socket开启，userId:{},examId:{},platform:{}", userId, examId, platform);

        // 加入列表
        sessionMap.put(this.buildKey(examId, userId), session);

        // 放入redis
        redisService.putList(examId, userId);

    }

    /**
     * 关闭链接
     * @param userId
     * @param examId
     * @param platform
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId,
                        @PathParam("examId") String examId,
                        @PathParam("platform") String platform) {

        log.info("++++++++++考试关闭，userId:{},courseId:{},fileId:{}", userId, examId, platform);
        this.remove(examId, userId);
    }

    /**
     * 出错关闭
     */
    @OnError
    public void onError(Throwable throwable, Session session,
                        @PathParam("userId") String userId,
                        @PathParam("examId") String examId,
                        @PathParam("platform") String platform) {

        try{
            this.remove(examId, userId);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 收到主动轮询消息
     * @param text
     * @throws IOException
     */
    @OnMessage
    public void onMsg(Session session, String text,
                      @PathParam("userId") String userId,
                      @PathParam("examId") String examId,
                      @PathParam("platform") String platform) throws IOException {

        log.info("++++++++++收到ping信息，msg:{},userId:{},examId:{},platform:{}", text, userId, examId, platform);
        session.getBasicRemote().sendText("pong");
    }

    /**
     * 发送消息
     * @param examId
     * @param userId
     * @param message
     * @throws IOException
     */
    public void send(String examId, String userId, String message) throws IOException {

        String key = this.buildKey(examId, userId);

        if(!sessionMap.containsKey(key)){
            throw new ServiceException("无法发送消息，用户可能不在线！");
        }

        Session session = sessionMap.get(key);

        if(session == null || !session.isOpen()){
            throw new ServiceException("获取会话错误，可能用户已离线！");
        }

        // 发送消息
        session.getBasicRemote().sendText(message);

    }

    /**
     * 根据考试批量发消息
     * @param examId
     * @param message
     * @throws IOException
     */
    public void sendAll(String examId, String message) throws IOException {


        if(sessionMap==null || sessionMap.isEmpty()){
            return;
        }

        for(String key: sessionMap.keySet()){
            // 指定考试发送
            if(!key.startsWith(examId)){
                continue;
            }

            Session session = sessionMap.get(key);
            if(session == null || !session.isOpen()){
                continue;
            }

            // 发送消息
            session.getBasicRemote().sendText(message);

        }

    }




    /**
     * 构建用户Map
     * @param examId
     * @param userId
     * @return
     */
    private String buildKey(String examId, String userId){
        return  new StringBuffer(examId).append("-").append(userId).toString();
    }

    /**
     * 移除会话
     */
    private void remove(String examId, String userId){

        // 移除Redis
        redisService.removeList(examId, userId);

        // 移除Map
        String key = this.buildKey(examId, userId);
        if(sessionMap.containsKey(key)){
            sessionMap.remove(key);
        }
    }
}
